#include "global.h"
#include "event_data.h"
#include "party_menu.h"
#include "task.h"
#include "constants/moves.h"
#include "constants/flags.h"
#include "event_scripts.h"

extern EWRAM_DATA struct PartyMenuInternal *sPartyMenuInternal;

enum {
    MENU_SUMMARY,
    MENU_SWITCH,
    MENU_CANCEL1,
    MENU_ITEM,
    MENU_GIVE,
    MENU_TAKE_ITEM,
    MENU_MAIL,
    MENU_TAKE_MAIL,
    MENU_READ,
    MENU_CANCEL2,
    MENU_SHIFT,
    MENU_SEND_OUT,
    MENU_ENTER,
    MENU_NO_ENTRY,
    MENU_STORE,
    MENU_REGISTER,
    MENU_TRADE1,
    MENU_TRADE2,
    MENU_TOSS,
    MENU_FIELD_MOVES
};

enum {
    FIELD_MOVE_CUT,         // FLAG_BADGE01_GET
    FIELD_MOVE_FLASH,       // FLAG_BADGE02_GET
    FIELD_MOVE_ROCK_SMASH,  // FLAG_BADGE03_GET
    FIELD_MOVE_STRENGTH,    // FLAG_BADGE04_GET
    FIELD_MOVE_SURF,        // FLAG_BADGE05_GET
    FIELD_MOVE_FLY,         // FLAG_BADGE06_GET
    FIELD_MOVE_DIVE,        // FLAG_BADGE07_GET
    FIELD_MOVE_WATERFALL,   // FLAG_BADGE08_GET
    FIELD_MOVE_TELEPORT,
    FIELD_MOVE_DIG,
    FIELD_MOVE_SECRET_POWER,
    FIELD_MOVE_MILK_DRINK,
    FIELD_MOVE_SOFT_BOILED,
    FIELD_MOVE_SWEET_SCENT,
    FIELD_MOVES_COUNT
};

struct PartyMenuInternal
{
    TaskFunc task;
    MainCallback exitCallback;
    u32 chooseHalf:1;
    u32 lastSelectedSlot:3;  // Used to return to same slot when going left/right bewtween columns
    u32 spriteIdConfirmPokeball:7;
    u32 spriteIdCancelPokeball:7;
    u32 messageId:14;
    u8 windowId[3];
    u8 actions[8];
    u8 numActions;
    // In vanilla Emerald, only the first 0xB0 hwords (0x160 bytes) are actually used.
    // However, a full 0x100 hwords (0x200 bytes) are allocated.
    // It is likely that the 0x160 value used below is a constant defined by
    // bin2c, the utility used to encode the compressed palette data.
    u16 palBuffer[BG_PLTT_SIZE / sizeof(u16)];
    s16 data[16];
};

static const u16 sFieldMoves[FIELD_MOVES_COUNT + 1] =
{
    [FIELD_MOVE_CUT]          = MOVE_CUT,
    [FIELD_MOVE_FLASH]        = MOVE_FLASH,
    [FIELD_MOVE_ROCK_SMASH]   = MOVE_ROCK_SMASH,
    [FIELD_MOVE_STRENGTH]     = MOVE_STRENGTH,
    [FIELD_MOVE_SURF]         = MOVE_SURF,
    [FIELD_MOVE_FLY]          = MOVE_FLY,
    [FIELD_MOVE_DIVE]         = MOVE_DIVE,
    [FIELD_MOVE_WATERFALL]    = MOVE_WATERFALL,
    [FIELD_MOVE_TELEPORT]     = MOVE_TELEPORT,
    [FIELD_MOVE_DIG]          = MOVE_DIG,
    [FIELD_MOVE_SECRET_POWER] = MOVE_SECRET_POWER,
    [FIELD_MOVE_MILK_DRINK]   = MOVE_MILK_DRINK,
    [FIELD_MOVE_SOFT_BOILED]  = MOVE_SOFT_BOILED,
    [FIELD_MOVE_SWEET_SCENT]  = MOVE_SWEET_SCENT,
    // NOTE: This value is used as the terminal value for the table. There's no reason to do this, as the size of the table is known.
    //       Whichever move shares this value (MOVE_SWORDS_DANCE by default) if present will be treated as the end of the array rather than a field move.
    [FIELD_MOVES_COUNT]       = FIELD_MOVES_COUNT
};

void NewSetPartyMonFieldSelectionActions(struct Pokemon *mons, u8 slotId)
{
    u8 i, j;
    bool8 addFieldMoves_Flash = FALSE;
    bool8 addFieldMoves_Fly = FALSE;

    sPartyMenuInternal->numActions = 0;
    AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_SUMMARY);

    // Add field moves to action list
    for (i = 0; i < MAX_MON_MOVES; i++)
    {
        for (j = 0; j != FIELD_MOVES_COUNT; j++)
        {
            if (sPartyMenuInternal->numActions >= 5)
            {
                break;
            }
            if (Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE && sFieldMoves[j] == MOVE_FLY && FlagGet(FLAG_BADGE06_GET) && !addFieldMoves_Fly)
            {
                AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, j + MENU_FIELD_MOVES);
                addFieldMoves_Fly = TRUE;
                continue;
            }
            if (gMapHeader.cave && sFieldMoves[j] == MOVE_FLASH && FlagGet(FLAG_BADGE02_GET) && !addFieldMoves_Flash)
            {
                AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, j + MENU_FIELD_MOVES);
                addFieldMoves_Flash = TRUE;
                continue;
            }
            if (GetMonData(&mons[slotId], i + MON_DATA_MOVE1) == sFieldMoves[j])
            {
                AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, j + MENU_FIELD_MOVES);
                break;
            }
        }
    }

    if (!InBattlePike())
    {
        if (GetMonData(&mons[1], MON_DATA_SPECIES) != 0)
            AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_SWITCH);
    }

    if (!InBattlePike())
    {
        if (ItemIsMail(GetMonData(&mons[slotId], MON_DATA_HELD_ITEM)))
            AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_MAIL);
        else
            AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_ITEM);
    }
    AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_CANCEL1);
}

const u8 *GetInteractedWaterScript(struct MapPosition *unused1, u8 metatileBehavior, u8 direction)
{
    if (FlagGet(FLAG_BADGE05_GET) == TRUE && IsPlayerFacingSurfableFishableWater() == TRUE)
        return EventScript_UseSurf;

    if (MetatileBehavior_IsWaterfall(metatileBehavior) == TRUE)
    {
        if (FlagGet(FLAG_BADGE08_GET) == TRUE && IsPlayerSurfingNorth() == TRUE)
            return EventScript_UseWaterfall;
        else
            return EventScript_CannotUseWaterfall;
    }
    return NULL;
}
